D3 笔记

  • D3 笔记已关闭评论
  • 154 次浏览
  • A+
所属分类:Web前端
摘要

D3 or D3.js 代表 “Data Driven Documents”select() 方法从文档中选择一个元素,它接收目标元素的名称作为参数并返回第一个匹配该名称 HTML 节点。举例:


D3

D3 or D3.js 代表 "Data Driven Documents"

选中、添加元素

select() 方法从文档中选择一个元素,它接收目标元素的名称作为参数并返回第一个匹配该名称 HTML 节点。举例:

const anchor = d3.select('a'); 

append()方法接收添加到文档中的元素,它会把该元素添加到一个选中的 HTML 节点,然后返回对该节点的引用。

text()方法可以设置被选中节点的文本也可以得到当前文本。若是设置文本,需要将字符串作为参数传递。

D3 允许方法的嵌套。

下面是一个选中无序列表,并添加一个 list 元素的方法:

d3.select("ul") 	.append("li") 	.text("very important") 

选中一组元素

使用 selectAll() 选中一组元素。它返回一个 HTML 节点数组。

下面是一个选中所有超链接元素的例子:

const anchors = d3.selectAll("a"); 

例子:

d3.selectAll("li")   .text("list item") 

使用数据

首先使用 data() 方法去选择 DOM 元素来和数据联系在一起。数据集作为参数传给该方法。

使用 enter() 方法为数据集中每一块元素创建一个新的 DOM 元素。

下面的例子是选择 ul 元素并根据数组创建列表。

const dataset = ["a", "b", "c"]; d3.select("ul").selectAll("li") 	.data(dataset) 	.enter() 	.append("li") 	.text("New Item"); 

使用动态数据

text() 方法可以接收字符串或者回调函数作为参数。

selection.text((d) => d) 

在上面的这个方法中,参数 d 指的是该数据集的一个入口。

<body>   <script>     const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];      d3.select("body").selectAll("h2")       .data(dataset)       .enter()       .append("h2")       // Add your code below this line        .text((d) => d + " USD");        // Add your code above this line   </script> </body>  /* 12 USD  31 USD  22 USD  17 USD  25 USD  18 USD  29 USD  14 USD  9 USD */ 

给元素加内联样式

使用 style() 各动态元素添加样式。该方法接收一个以逗号 , 分隔的键值对作为参数。

下面是一个把选中文本设置为蓝色的例子:

selection.style("color","blue"); 

设置选中字体:

d3.select("body")   .style("font-family","verdana"); 

基于数据改动样式

style() 中同样可以使用回调函数来改动不同元素的样式。使用参数 d 来代表数据点。

下面的例子是把数据集中小于 20 的元素设置为红色,其它设置为绿色。

d3.selectAll("h2")   .style("color", (d) => {     if (d < 20) {       return "red";     } else return "green";   }); 

添加 class 属性

attr() 方法和 style() 方法类似,他接收以逗号分割的值,并且可以使用回调函数。

下面是一个给元素添加 container class 的例子。

selection.attr("class", "container"); 

动态修改元素的高度

结合上面所学创建一个条形图 (bar chart)。

<style>   .bar {     width: 25px;     height: 100px;     display: inline-block;     background-color: blue;   } </style> <body>   <script>     const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];      d3.select("body").selectAll("div")       .data(dataset)       .enter()       .append("div")       .attr("class", "bar") 			.style("height", (d) => d + "px");   </script> </body> 

改变条形图的展示

<style>   .bar {     width: 25px;     height: 100px;     /* Add your code below this line */     marign: 2px;     /* Add your code above this line */     display: inline-block;     background-color: blue;   } </style> <body>   <script>     const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];      d3.select("body").selectAll("div")       .data(dataset)       .enter()       .append("div")       .attr("class", "bar")       .style("height", (d) => (d*10 + "px")) // Change this line   </script> </body> 

SVG in d3

SVG 的全称是:Scalable Vector Graphics。

scalable 的意思是对物体放大或者缩小不会使物体马赛克(pixelated)。

SVG 在 HTML 中使用 svg 标签实现。

下面是一个创建 SVG 的例子:

<style>   svg {     background-color: pink;   } </style> <body>   <script>     const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];      const w = 500;     const h = 1     00;      const svg = d3.select("body")                   // Add your code below this line  svg.append("svg").attr("width",w).attr("height",h);                   // Add your code above this line   </script> </body> 

SVG 形状

SVG 支持多种数量的形状,例如:使用 <rect> 来表示矩形。

当把一个形状放入 SVG 区域时,可以设置 x,y 坐标系。原点(0,0)表示左上角。x 的正值会使图形向右移动,y 的正值向上移动。例如:把一个形状放在 500 宽,100 高的位置需要设置 x = 250,y = 50。

对于 <rect> 来说,它有四个属性,分别是高度、宽度和 x,y。该元素必须添加到 svg节点,而不是 body 节点。

下面的例子是设置一个矩形

<body>   <script>     const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];      const w = 500;     const h = 100;      const svg = d3.select("body")                   .append("svg")                   .attr("width", w)                   .attr("height", h)                   // Add your code below this line svg.append("rect") .attr("width", 25) .attr("height", 100) .attr("x", 0) .attr("y", 0);                   // Add your code above this line   </script> </body> 

对数据集中的每一个数据点创建一个 bar

<body>   <script>     const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];      const w = 500;     const h = 100;      const svg = d3.select("body")                   .append("svg")                   .attr("width", w)                   .attr("height", h);     svg.selectAll("rect")        // Add your code below this line .data(dataset) .enter() .append("rect")        // Add your code above this line        .attr("x", 0)        .attr("y", 0)        .attr("width", 25)        .attr("height", 100);   </script> </body> 

对每个 bar 动态设置坐标

条形图的 y 坐标应该是一致的,而 x 坐标应该有所不同。通过设置 attr() 的回调函数来动态设置。回调函数接收两个参数,第一个用 d 代表数据点本身,第二个代表数据点在数组中的索引。格式:

selection.attr("property", (d,i) => {    }) 

注:不需要使用 for 或者 forEach() 循环。

下面是扩大 30 倍的例子:

<body>   <script>     const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];      const w = 500;     const h = 100;      const svg = d3.select("body")                   .append("svg")                   .attr("width", w)                   .attr("height", h);     svg.selectAll("rect")        .data(dataset)        .enter()        .append("rect")        .attr("x", (d, i) => {          // Add your code below this line return i*30;          // Add your code above this line        })        .attr("y", 0)        .attr("width", 25)        .attr("height", 100);   </script> </body> 

动态改变高度

实际上就是修改数据点

<body>   <script>     const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];      const w = 500;     const h = 100;      const svg = d3.select("body")                   .append("svg")                   .attr("width", w)                   .attr("height", h);      svg.selectAll("rect")        .data(dataset)        .enter()        .append("rect")        .attr("x", (d, i) => i * 30)        .attr("y", 0)        .attr("width", 25)        .attr("height", (d, i) => {          // Add your code below this line return d * 3;          // Add your code above this line        });   </script> </body> 

倒置 SVG 元素

y 坐标也就是 y = heightOfSVG - heightOfBar 会把 bar 置于右上侧。

一般公式:y = h - m * d,其中 m 是数据点 scale 的常量。

<body>   <script>     const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];      const w = 500;     const h = 100;      const svg = d3.select("body")                   .append("svg")                   .attr("width", w)                   .attr("height", h);     svg.selectAll("rect")        .data(dataset)        .enter()        .append("rect")        .attr("x", (d, i) => i * 30)        .attr("y", (d, i) => {          // Add your code below this line return 100 - 3 * d;          // Add your code above this line        })        .attr("width", 25)        .attr("height", (d, i) => 3 * d);   </script> </body> 

改变 SVG 图片的颜色

在 SVG 中,rect 形状使用 fill 来控制颜色。

下面设置颜色为海军蓝。

<body>   <script>     const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];      const w = 500;     const h = 100;      const svg = d3.select("body")                   .append("svg")                   .attr("width", w)                   .attr("height", h);     svg.selectAll("rect")        .data(dataset)        .enter()        .append("rect")        .attr("x", (d, i) => i * 30)        .attr("y", (d, i) => h - 3 * d)        .attr("width", 25)        .attr("height", (d, i) => 3 * d)        // Add your code below this line .attr("fill", "navy");        // Add your code above this line   </script> </body> 

加标签

使用 SVG 的 text 给元素加标签。该属性同样具有 x 和 y 属性。

<body>   <script>     const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];      const w = 500;     const h = 100;      const svg = d3.select("body")                   .append("svg")                   .attr("width", w)                   .attr("height", h);      svg.selectAll("rect")        .data(dataset)        .enter()        .append("rect")        .attr("x", (d, i) => i * 30)        .attr("y", (d, i) => h - 3 * d)        .attr("width", 25)        .attr("height", (d, i) => 3 * d)        .attr("fill", "navy");      svg.selectAll("text")        .data(dataset)        .enter()        // Add your code below this line  .append("text")        .attr("x", (d, i) => i * 30)        .attr("y", (d, i) => h - 3 * d - 3)        .text((d, i) => d);        // Add your code above this line   </script> <body> 

给标签加样式

<body>   <script>     const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];      const w = 500;     const h = 100;      const svg = d3.select("body")                   .append("svg")                   .attr("width", w)                   .attr("height", h);      svg.selectAll("rect")        .data(dataset)        .enter()        .append("rect")        .attr("x", (d, i) => i * 30)        .attr("y", (d, i) => h - 3 * d)        .attr("width", 25)        .attr("height", (d, i) => d * 3)        .attr("fill", "navy");      svg.selectAll("text")        .data(dataset)        .enter()        .append("text")        .text((d) => d)        .attr("x", (d, i) => i * 30)        .attr("y", (d, i) => h - (3 * d) - 3)        // Add your code below this line .attr("fill","red") .style("font-size", "25px")        // Add your code above this line   </script> </body> 

给元素添加 hover 效果

<style>   .bar:hover {     fill: brown;   } </style> <body>   <script>     const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];      const w = 500;     const h = 100;      const svg = d3.select("body")                   .append("svg")                   .attr("width", w)                   .attr("height", h);      svg.selectAll("rect")        .data(dataset)        .enter()        .append("rect")        .attr("x", (d, i) => i * 30)        .attr("y", (d, i) => h - 3 * d)        .attr("width", 25)        .attr("height", (d, i) => 3 * d)        .attr("fill", "navy")        // Add your code below this line 			.attr("class", "bar")        // Add your code above this line      svg.selectAll("text")        .data(dataset)        .enter()        .append("text")        .text((d) => d)        .attr("x", (d, i) => i * 30)        .attr("y", (d, i) => h - (3 * d) - 3);    </script> </body> 

给元素添加 tooltip

当用户 hover 在一个元素上,tooltip 可以展示更多的信息。

使用 SVG 的 title 给元素添加 tooltip。使用 title 配合 text() 方法给条动态添加数据。

下面是一个例子:

<style>   .bar:hover {     fill: brown;   } </style> <body>   <script>     const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];     const w = 500;     const h = 100;     const svg = d3.select("body")                   .append("svg")                   .attr("width", w)                   .attr("height", h);     svg.selectAll("rect")        .data(dataset)        .enter()        .append("rect")        .attr("x", (d, i) => i * 30)        .attr("y", (d, i) => h - 3 * d)        .attr("width", 25)        .attr("height", (d, i) => d * 3)        .attr("fill", "navy")        .attr("class", "bar")        // Add your code below this line   .append("title")   .text((d) => {     return d;   })        // Add your code above this line     svg.selectAll("text")        .data(dataset)        .enter()        .append("text")        .text((d) => d)        .attr("x", (d, i) => i * 30)        .attr("y", (d, i) => h - (d * 3 + 3))   </script> </body> 

使用 SVG 环形创建 scatterplot

scatterplot 是另一种可视化的类型。它使用圆环来遍历数据点,每个数据点有两个值。这些值和 x、y 坐标绑定,用来定位圆环的位置。

SVG 的 circle 标签创建圆形。

下面是一个圆形的例子:

<body>   <script>     const dataset = [                   [ 34,    78 ],                   [ 109,   280 ],                   [ 310,   120 ],                   [ 79,    411 ],                   [ 420,   220 ],                   [ 233,   145 ],                   [ 333,   96 ],                   [ 222,   333 ],                   [ 78,    320 ],                   [ 21,    123 ]                 ];     const w = 500;     const h = 500;     const svg = d3.select("body")                   .append("svg")                   .attr("width", w)                   .attr("height", h);     svg.selectAll("circle")        // Add your code below this line .data(dataset) .enter() .append("circle");        // Add your code above this line   </script> </body> 

给圆形添加属性

圆形主要有三个属性。cxcy 属性是坐标系。r 属性规定圆形的半径。

这三个属性可以使用一个回调函数动态设置它们的值。记住,所有在 data(dataset) 链后的方法会对每个数据项运行一次。回调函数中的 d 表示当前数据集合中的数据项。可以使用括号表示法去得到数据集中的元素,如:d[0]

下面是一个例子:

<body>   <script>     const dataset = [                   [ 34,    78 ],                   [ 109,   280 ],                   [ 310,   120 ],                   [ 79,    411 ],                   [ 420,   220 ],                   [ 233,   145 ],                   [ 333,   96 ],                   [ 222,   333 ],                   [ 78,    320 ],                   [ 21,    123 ]                 ];      const w = 500;     const h = 500;      const svg = d3.select("body")                   .append("svg")                   .attr("width", w)                   .attr("height", h);     svg.selectAll("circle")        .data(dataset)        .enter()        .append("circle")        // Add your code below this line .attr("cx", (d) => d[0]) .attr("cy", (d) => h - d[1]) .attr("r", 5)        // Add your code above this line   </script> </body> 

给 scatterplot 添加标签

<body>   <script>     const dataset = [                   [ 34,    78 ],                   [ 109,   280 ],                   [ 310,   120 ],                   [ 79,    411 ],                   [ 420,   220 ],                   [ 233,   145 ],                   [ 333,   96 ],                   [ 222,   333 ],                   [ 78,    320 ],                   [ 21,    123 ]                 ];     const w = 500;     const h = 500;     const svg = d3.select("body")                   .append("svg")                   .attr("width", w)                   .attr("height", h);     svg.selectAll("circle")        .data(dataset)        .enter()        .append("circle")        .attr("cx", (d, i) => d[0])        .attr("cy", (d, i) => h - d[1])        .attr("r", 5);     svg.selectAll("text")        .data(dataset)        .enter()        .append("text")        // Add your code below this line        .attr("x", (d) => d[0] + 5)        .attr("y", (d) => h - d[1])        .text((d) => (d[0] + ", " + d[1]))        // Add your code above this line   </script> </body> 

创建线性 scale

scales 是一种函数,可以把数据集的数据映射为 SVG 画布。

例子:

const scale = d3.scaleLinear(); 

默认情况,scale 使用实体关系。输入和输出的结果相同。

<body>   <script>     // Add your code below this line     const scale = d3.scaleLinear(); // Create the scale here     const output = scale(50); // Call scale with an argument here     // Add your code above this line     d3.select("body")       .append("h2")       .text(output);   </script> </body> 

给 scale 设置 domain 和 range

假如一个数据集范围从50 - 480,这是输入的范围,也叫 domain。

然后打算把这些数据点映射到 x 轴上,从 10 units 到 500 units,这就是输出的范围,也叫 range。

domian()range() 方法为 scale 设置这些值。这两个方法接收一个至少包含两个元素数组作为参数。例如:

scale.domain([50, 480]); scale.range([50, 480]); scale(40); d3.scaleLinear(); 

最小的 domain 是 50 映射到最小的 range 为 10。

例子:

<body>   <script>     // Add your code below this line     const scale = d3.scaleLinear(); scale.domain([250, 500]).range([10, 150]);     // Add your code above this line     const output = scale(50);     d3.select("body")       .append("h2")       .text(output);   </script> </body> 

使用 d3.max 和 d3.min 方法找出数据集的最大和最小元素

例子:

const exampleData = [3, 45, 10, 9]; d3.min(exampleData); d3.max(exampleData); 

有些时候数据集是嵌套的,这样的情况下,需要给这两个函数传入回调函数。这时,参数 d 代表当前内部的数组。

const locationData = [[1, 7],[6, 3],[8, 3]]; const minX = d3.min(locationData, (d) => d[0]); // minX = 1;  <body>   <script>     const positionData = [[1, 7, -4],[6, 3, 8],[2, 9, 3]]     // Add your code below this line     const output = d3.max(positionData, (d) => d[2]); // Change this line     // Add your code above this line     d3.select("body")       .append("h2")       .text(output)   </script> </body> // output = 8; 

使用动态 scale

<body>   <script>     const dataset = [                   [ 34,    78 ],                   [ 109,   280 ],                   [ 310,   120 ],                   [ 79,    411 ],                   [ 420,   220 ],                   [ 233,   145 ],                   [ 333,   96 ],                   [ 222,   333 ],                   [ 78,    320 ],                   [ 21,    123 ]                 ];     const w = 500;     const h = 500;     // Padding between the SVG canvas boundary and the plot     const padding = 30;     // Create an x and y scale     const xScale = d3.scaleLinear()                     .domain([0, d3.max(dataset, (d) => d[0])])                     .range([padding, w - padding]);     // Add your code below this line  const yScale = d3.scaleLinear()   .domain([0, d3.max(dataset, (d) => d[1])])   .range([h - padding, padding]);     // Add your code above this line     const output = yScale(411); // Returns 30     d3.select("body")       .append("h2")       .text(output)   </script> </body> 

使用预定义的 scale 放置元素

<body>   <script>     const dataset = [       [  34,  78 ],       [ 109, 280 ],       [ 310, 120 ],       [  79, 411 ],       [ 420, 220 ],       [ 233, 145 ],       [ 333,  96 ],       [ 222, 333 ],       [  78, 320 ],       [  21, 123 ]     ];          const w = 500;     const h = 500;     const padding = 60;          const xScale = d3.scaleLinear()       .domain([0, d3.max(dataset, (d) => d[0])])       .range([padding, w - padding]);          const yScale = d3.scaleLinear()       .domain([0, d3.max(dataset, (d) => d[1])])       .range([h - padding, padding]);          const svg = d3.select("body")       .append("svg")       .attr("width", w)       .attr("height", h);          svg.selectAll("circle")       .data(dataset)       .enter()       .append("circle")       .attr("cx", (d) => xScale(d[0]))       .attr("cy", (d) => yScale(d[1]))       .attr("r", 5);            svg.selectAll("text")       .data(dataset)       .enter()       .append("text")       .text((d) =>  (d[0] + ", " + d[1]))       .attr("x", (d) => xScale(d[0] + 10))       .attr("y", (d) => yScale(d[1]));   </script> </body> 

加入 Axes

axisLeft()axisBottom() 方法,去渲染 x 轴和 y 轴,相对的,根据 xScale 创建 xAxis

const xAxis = d3.axisBottom(xScale); 

下一步就是渲染

svg.append("g") 	 .attr("transform", "translate(0, " + (h - padding) + ")") 	 .call(xAxis);