世外天堂
返回首页 2025年4月8日11 分钟阅读约 3395 字 热度 --

D3基础入门

在做 Node Library 依赖关系分析工具时,需要用可视化来实现依赖之间的关系,暂时决定使用 d3.js 的力有向图,后续可能会修改。故,学习了 d3 的一些基础的语法,将其和 echarts 可视化进行了对比。如果小伙伴们感兴趣,可以仔细看看。

#D3 #图形

前言

在做 Node Library 依赖关系分析工具时,需要用可视化来实现依赖之间的关系,暂时决定使用 d3.js 的力有向图,后续可能会修改。故,学习了 d3 的一些基础的语法,将其和 echarts 可视化进行了对比。如果小伙伴们感兴趣,可以仔细看看。

✨ 为什么选择D3.js

➡ d3 优点

  • 数据驱动视图 --将数据与DOM元素绑定,根据数据动态地生成图表和可视化效果
  • 代码十分简洁
  • 擅长矢量图形,缩放不损失图形精度,不擅长位图和瓦片,不擅长探索型可视化;

➡ 什么时候选择D3 ?什么时候选择echarts?

对于客户需求要求的图表拥有大量的用户交互场景,用 d3 比较方便,因为 d3 中 svg 画图支持事件处理器,他是基于 dom 进行操作的。

对于大量的数据展示并且对于用户交互场景没什么要求,就只是展示数据,那我建议使用 echarts,如果使用 d3 的话展示的每一个数据都是一个标签,那么当数据发生改变的时候这时候图表会重新渲染,会不停的操作 dom,操作 dom 是很耗费性能的。【简单版本:D3操作DOM,没什么交互的话,选择echarts】

从兼容性方面考虑:echarts 兼容到 IE6 及以上的所有主流浏览器,而 d3 兼容 IE9 及以上以及所有的主流浏览器,如果项目考虑兼容 IE6,建议使用 echarts。

✨ d3基础语法

1️⃣ 总结一下 D3 可视化的基本步骤如下:

  • 创建新元素并绑定数据(html的元素可理解为划定区域和声明类型的闭合标签,如p表示其是一个段落,是段落就可以有段落文本、长宽、id等属性和标识);
  • 设置相应元素的可视属性,将数据值映射为元素大小、颜色、位置等可视属性;
  • 对元素进行排列和变换,还有响应交互;

2️⃣ Svg 基础知识了解

SVG(Scalable Vector Graphics,可伸缩矢量图形)基于XML标签来表示图形。基于HTML文档的可视化基本都使用canvas或svg元素作为数据到图形的映射容器。D3也可以直接操作div或其他原生HTML元素来绘图,但这就显得笨重不灵活,且容易出现浏览器间不一致的问题。而用 SVG就更可靠,图形效果更一致,且绘图速度更快。

SVG 元素可以理解为能在上面绘制各种形状的画布。

简单一句话概括: svg 是一个可伸缩矢量图形,缩放不损失图形精度

3️⃣ 具体应用

🟠 元素定位和数据绑定

简单介绍D3如何选择及增删文档对象的方法以及数据绑定的方法

元素定位

🔸 选择元素

select() 方法 :用于选择单个元素的常用方法。

示例:

假设 HTML 中有如下的 DOM 结构:

<div id="example">
   <p>Hello, D3.js!</p>
</div>
// 你可以使用 D3.js 的 `select()` 方法来选择 `<p>` 元素,并对其进行操作:

// 选择 <p> 元素
const pElement = d3.select("p");

// 对选中的 <p> 元素进行样式设置
pElement.style("color", "blue");
pElement.style("font-size", "20px");
d3.select("body"); //选择HTML里的body元素;
d3.select("#apple"); //选择id为apple的元素;例如会匹配上<p id="apple">一段文本</p>;
d3.select(".apple"); //选择class为apple的元素;会匹配上<p class="apple">一段文本</p>;

如果想获得所有满足条件的元素,用 selectAll() 方法,写法和上面一致,把 select 变成 selectAll

// react
const LinePlot = (props) => {
  const svgRef = useRef(null);
  const gdefs = d3.create("svg:defs");
  const svg = d3.select(svgRef.current);

  svg.append(() => gdefs.node());

  gdefs.selectAll("marker");

  return (
    <div>
      {/* 将 SVG 元素插入到 DOM 中 */}
      <svg ref={svgRef}></svg>
    </div>
  );
};

🔸 添加元素

append() 方法:添加元素

// 创建一个 SVG 元素
const svg = d3.create("svg");

// 在html文档里的<svg>标签下从无到有地增加了一个<rect></rect>元素;
svg.append("rect");

设定属性

🔸 选定或添加我们需要操纵的元素后,便可以编辑元素的属性,例如图形位置、填充色、标识等属性。通过 .attr(name,value) 给所选元素添加属性,name是属性名称,value是属性值。

const svg = d3.select(svgRef.current)
  .attr("viewBox", [-width / 2, -height / 2, width, height])
  .attr("width", width)
  .attr("height", height)
  .attr(
    "style",
    "max-width: 100%; height: auto; font: 12px sans-serif;"
  );

数据绑定

🔸 通过 data(vals[,key]) 绑定数组 vals 中的每一项到选中的元素,key是一个用于指定绑定规则的函数。

gdefs
  .selectAll("marker")
  .data(types) // 使用 data() 方法绑定数据
  .join("marker") // 根据数据绑定状态对元素进行操作
  .attr("id", d => `arrow-${d}`)
  .attr("viewBox", "0 -5 10 10")
  .attr("refX", 15)
  .attr("refY", -0.5)
  .attr("markerWidth", 6)
  .attr("markerHeight", 6)
  .attr("orient", "auto") // 定义图形在路径上的朝向
  .append("path") // append 添加 用于绘制路径,例如曲线、线段等。主要用于箭头
  .attr("fill", color)
  .attr("d", "M0,-5L10,0L0,5");

读取本地数据

🔸 d3.csv("food.csv", function(data) {dataset=data;}) 可以读取本地的 csv 文件数据进行使用

d3.csv("bar-data.csv", function(dataset) {
  d3.select("body")
    .selectAll("svg")
    .data(dataset)
    .enter()
    .append("svg")
    .style("background-color","#1EAFAE")
    .attr("width",50)
    .attr("height",function(d){return d*10 +"px";});
});

🟡 SVG预定义元素

🔸 以下是 SVG 中的一些常见预定义元素:

预定义元素定义
<rect>矩形元素,用于绘制矩形。可以设置矩形的位置、宽度、高度以及圆角属性。
<circle>圆形元素,用于绘制圆形。可以设置圆心的坐标和半径。
<ellipse>椭圆元素,用于绘制椭圆。可以设置椭圆的中心坐标和水平、垂直半径。
<line>直线元素,用于绘制直线。可以设置直线的起始点和终点坐标。
<polyline>折线元素,用于绘制由多个连接的线段组成的折线。
<polygon>多边形元素,用于绘制封闭的多边形。
<path>路径元素,用于通过路径命令绘制任意复杂的图形。
<text>分组元素,用于将多个 SVG 元素组合在一起。
<marker>容器元素,用于定义标记图形样式。

🔸 一些通用属性:

通用属性含义
fill表示要填充的颜色
stroke表示边框的颜色
stroke-width边框宽度
opacity透明度

💠 <rect> 元素

属性:

  • x:矩形左上角的x坐标;
  • y:矩形左上角的y坐标;
  • width:矩形宽度;
  • height:矩形高;
  • rx:圆角矩形x方向半径;
  • ry:圆角矩形y方向半径;

💠 <circle> 元素

属性:

  • cx:圆心的x坐标;
  • cy:圆心的y坐标;
  • r:圆的半径;

💠 <ellipse> 元素

属性:

  • cx:椭圆圆心的x坐标;
  • cy:圆心的y坐标;
  • rx:椭圆的水平半径;
  • ry:椭圆的垂直半径;

💠 <line> 元素

属性:

  • x1:起点的x坐标;
  • y1:起点的y坐标;
  • x2:终点的x坐标;
  • y2:终点的y坐标;

💠 <path> 元素

<path> 的写法是:给出一个坐标点,在坐标点前面添加一个英文字母,用于标识如何运动到此坐标点。

英文字母按照功能可分为五类。大写表示绝对坐标,小写表示相对坐标。

分类:

移动类:

  • M 即 moveto

直线类:

  • L
  • H
  • V

曲线类:

  • C
  • S
  • Q
  • T

弧线类:

  • A

闭合类:

  • Z
// 创建 <g> 元素并添加链接(<path>)
const link = gLink
  .attr("fill", "none")
  .attr("stroke-width", 1.5)
  .selectAll("path")
  .data(graph)
  .join("path")
  .attr("stroke", d => color(d.type))
  .attr("marker-end", d => `url(${new URL(`#arrow-${d.type}`, location)})`);

// 节点拖动时,路径重新指向
function linkArc(d) {
  const r = Math.hypot(
    d.target.x - d.source.x,
    d.target.y - d.source.y
  );

  return `
    M${d.source.x},${d.source.y}
    A${r},${r} 0 0,1 ${d.target.x},${d.target.y}
  `;
}

simulation.on("tick", () => {
  link.attr("d", linkArc);
  node.attr("transform", d => `translate(${d.x},${d.y})`);
});

上一篇

手把手教你解决web前端跨域问题

下一篇

正则表达式详解

评论